package tallinn;



import java.util.ArrayList;
import java.util.Random;

import processing.core.PApplet;
import reactionDiffusion.ReactDiffuseAppletFloat;
import simpleGeom.Box3D;
import simpleGeom.Grid3DFloat;
import simpleGeom.Line3D;
import simpleGeom.MMesh;
import simpleGeom.SimpleMCube;
import simpleGeom.Vec3D;
import simpleGui.PCamera3D;


public class SimpleTallinReactDiffuse extends PApplet{
Grid3DFloat grid;


SimpleMCube smCube;
PCamera3D cam;
ReactDiffuseAppletFloat rApp;

Grid3DFloat diffGrid;
Random random;
MMesh mMesh;
String input;
public void setup(){
	size(1600,800,OPENGL);
	
	 mMesh=new MMesh();
	mMesh.loadOBJ(input);
	println("q: "+mMesh.quads.length);
	println("t: "+mMesh.triangles.length);
	Box3D bds=mMesh.getBounds();
	Box3D oBd=bds.getOffsetBox(1);
	println(mMesh.getBounds());
	mMesh.triangulateQuads();
	//mMesh.scale(0.001f, 0.001f, 0.001f);
	
	float dim=0.1f;
	cam = new PCamera3D(this,0.5f,0.1f);
	grid=new Grid3DFloat((int)(oBd.getDimX()/dim),(int)(oBd.getDimY()/dim),(int)(oBd.getDimZ()/dim));
	grid.dim=dim;
	
	
	grid.x1=oBd.x1;
	grid.y1=oBd.y1;
	grid.z1=oBd.z1;
	mMesh.scanMeshDistance(grid.x1, grid.y1,grid.z1, grid.nX, grid.nY, grid.nZ, grid.dim, grid.dim*3f, grid.values);

	//grid.saveObj(grid.dim, this.selectOutput());
	
	float sX=120;
	float sY=12;
	float sZ=15;
	grid.dim=1;
	rApp=new ReactDiffuseAppletFloat(grid.nX/2, grid.nY/2, grid.nZ/4);
	rApp.iSetting=rApp.PATTERN_TEST;// cheetah ok //COLONY PATTERN_FINGERPRINT
	rApp.random=new Random(0);
	rApp.setupReaction();
	diffGrid=new Grid3DFloat(grid.nX/2, grid.nY/2, grid.nZ/4);
	geomGrid=new Grid3DFloat(grid.nX,grid.nY,grid.nZ);
	//reactDiffuse(1000);
	
	 
	smCube=new SimpleMCube();
}

public void reactDiffuse(int n){
	for (int i=0;i<n;i++){
		rApp.reactdiffuse();
	}
	
	rApp.copyValues(diffGrid.values);
	for (int x=0;x<rApp.nx;x++){
		for (int y=0;y<rApp.ny;y++){
			for (int z=0;z<rApp.nz;z++){
				if (z%4<2){
					//rValues[rApp.getIndex(x, y, z)]=0;
				}
			}
		}
	}
	normalize(diffGrid.values);	
}

public void normalize(float[] values){
	float minV=Float.POSITIVE_INFINITY;
	float maxV=Float.NEGATIVE_INFINITY;
	for (int i=0;i<values.length;i++){
		minV=Math.min(values[i], minV);
		maxV=Math.max(values[i], maxV);
	}
	for (int i=0;i<values.length;i++){
		values[i]=map(values[i],minV,maxV,0,1);
	}
}

float iso=0.8f;
Grid3DFloat geomGrid;
public void draw(){
	println("darw");
	lights();
	cam.apply(g);
	background(0);
	noStroke();
	scale(10);
	translate(grid.nX*-0.5f,grid.nY*-0.5f,grid.nZ*-0.5f);
	/*for (int x=0;x<42;x++){
		float cX=x*grid.nX/42f;
		beginShape(QUADS);
		vertex(cX,0,0);
		vertex(cX,grid.nY,0);
		vertex(cX,grid.nY,grid.nZ);
		vertex(cX,0,grid.nZ);
		endShape();
	}
	for (int z=0;z<6;z++){
		float cZ=z*grid.nZ/6f;
		beginShape(QUADS);
		vertex(0,0,cZ);
		vertex(0,grid.nY,cZ);
		vertex(grid.nX,grid.nY,cZ);
		vertex(grid.nX,0,cZ);
		endShape();
	}*/
	this.scale(1, 1, 1f);
	
	/*for (int i=0;i<rValues.length;i++){
		if (rValues[i]>iso)rValues[i]=1;
		if (rValues[i]<iso)rValues[i]=0;
	}*/
	/*diffGrid.normalize();
	//smCube.marchingCubes(diffGrid.nX, diffGrid.nY, diffGrid.nZ, diffGrid.values,iso, 1, 0, 0, 0, null);

	grid.mapLinear(diffGrid, grid);
	grid.blur(6);
	float d=1;
	
	System.arraycopy(grid.values, 0, geomGrid.values, 0, grid.values.length);
	calcD(grid.values,1);*/
	//drawWalls();
	//calcD(grid.values,iso);
	
	/*for (int x=0;x<grid.nX;x++){
		for (int y=0;y<grid.nY;y+=3){
			for (int z=0;z<grid.nZ;z+=3){
				grid.set(x,y,z, 1f);
			}
		}
	}
	for (int x=0;x<grid.nX;x+=4){
		for (int y=0;y<grid.nY;y++){
			for (int z=0;z<grid.nZ;z+=4){
				grid.set(x,y,z, 1f);
			}
		}
	}*/
	/*for (int i=0;i<5;i++){
		for (int j=0;j<4;j++){
		int startZ=i*grid.nZ/5+2;
		int endZ=(i+1)*grid.nZ/5-2;
		
		int startY=j*grid.nY/4+2;
		int endY=(j+1)*grid.nY/4-2;
		for (int z=startZ;z<endZ;z++){
			for (int y=startY;y<endY;y++){
				for (int x=0;x<grid.nX;x++){
					grid.set(x,y,z, 1);
				}
			}
		}
		}
	}*/
	/**/
	/*for (int x=0;x<grid.nX;x++){
		for (int y=0;y<grid.nY;y++){
			for (int z=2*grid.nZ/5;z<grid.nZ;z+=2*grid.nZ/5){
				
					if (geomGrid.get(x,y,z)>iso&&geomGrid.get(x,y,z)<iso*1.4f){
						grid.set(x,y,z, 0.00f);
						
					}
				}
			}
		}
	
	for (int x=0;x<grid.nX;x++){
		
			for (int z=0;z<grid.nZ;z++){
				if (geomGrid.get(x,grid.nY/2,z)<iso){
					
						grid.set(x,grid.nY/2,z, 0.02f);
						
					}
			}
		}
		*/
	/*for (int x=0;x<grid.nX;x++){
		for (int y=0;y<grid.nY;y++){
			for (int z=0;z<grid.nZ;z++){
				if (x==0||y==0||z==0||x==grid.nX-1||y==grid.nY-1||z==grid.nZ-1){
					grid.set(x,y,z, 0);
				}
			}
		}
	}*/
	/*quads=grid.createFaces(0.06f);
	beginShape(QUADS);
	for (int i=0;i<quads.length;i++){
		float x=grid.getX(quads[i]);
		float y=grid.getY(quads[i]);
		float z=grid.getZ(quads[i]);
		vertex(x,y,z);
	}
	endShape();*/
	grid.saveObj(0.2f, "tallinnBox02.obj");
	println("saved");
	//grid.normalize();
	if (doExport){
		println("doExport");
		doExport=false;
		smCube.marchingCubes(grid.nX, grid.nY, grid.nZ, grid.values,0.2f, 1, 0, 0, 0, "tallinn.obj");
		println("exported");
	}
	smCube.marchingCubes(grid.nX, grid.nY, grid.nZ, grid.values,0.2f, 1, 0, 0, 0, null);
	smCube.draw(g);
	
	mMesh.draw(g);
	
}
public void drawWalls(){
	for (int x=0;x<grid.nX;x++){
		for (int y=0;y<grid.nY;y++){
			for (int z=0;z<grid.nZ;z+=grid.nZ/5){
				
					if (geomGrid.get(x,y,z)<iso){
						grid.set(x,y,z, 0.00f);
						
					}
				}
			}
		}
	for (int x=0;x<grid.nX;x++){
			for (int z=0;z<grid.nZ;z++){
				
					if (geomGrid.get(x,grid.nY/2,z)<iso){
						grid.set(x,grid.nY/2,z, 0.00f);
						
					}
				}
			
		}
	for (int x=0;x<grid.nX;x+=grid.nX/42f){
		for (int y=0;y<grid.nY;y++){
			for (int z=0;z<grid.nZ;z++){
				
					if (geomGrid.get(x,y,z)<iso){
						grid.set(x,y,z, 0.00f);
						
					}
				}
			}
		}
}
int[] quads;
public void calcD(float[] values,float iso){
	for (int i=0;i<values.length;i++){
		values[i]=Math.abs(values[i]-iso);
	}
}
boolean doExport;
public void keyPressed(){
	if (key=='m'){
		iso= mouseY*1f/height;
		iso=this.constrain(iso, 0.1f, 0.9f);
		println(iso);
	}
	if (key=='e'){
		doExport=true;
	}
}
}
